<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
</head>
<body>
<script>
    const ctx = {
        body: {name: "测试数据", value: {id: 1}, status: true, type: 1, list: [1]}
    };

    class ParaseLitefraph {
        constructor(config) {
            this.config = config;
        }

        // 只能有一个路由入口
        getRouter() {
            const config = this.config;
            for (let i = 0; i < config.nodes.length; i++) {
                const node = config.nodes[i];
                if (node.type === "nodejs/Router") {
                    return node;
                }
            }
        }

        /**
         * 获取节点的所有流程插槽的链接
         * @param node
         * @returns {Array}
         */
        getNextNodes(node) {
            const nodes = [];
            for (let i = 0; i < node.outputs.length; i++) {
                const output = node.outputs[i];
                if (output.type === "ArrowFlow") {
                    if (output.links) {
                        const linkId = output.links[0];//只会有一个
                        nodes.push(this.getNextNodeByLinkId(linkId));
                    }
                }
            }
            return nodes
        }


        /**
         * 根据id获取对应的link
         * @param id
         */
        getLinkById(id) {
            const config = this.config;
            for (let i = 0; i < config.links.length; i++) {
                const link = config.links[i];
                if (link[0] === id) {
                    return link;
                }
            }
        }

        /**
         * 根据id获取对应的node
         * @param id
         */
        getNodeById(id) {
            const config = this.config;
            for (let i = 0; i < config.nodes.length; i++) {
                const node = config.nodes[i];
                if (node.id === id) {
                    return node;
                }
            }
        }

        /**
         * 根据linkID获取下一个节点
         */
        getNextNodeByLinkId(id) {
            const link = this.getLinkById(id);
            if (!link) {
                return;
            }
            // const [linkId,sourceId,outputId,targetId,inputId,type] = link;
            const tagetId = link[3];
            return this.getNodeById(tagetId);
        }

        //负责包装方法体
        runCpcRunCode(node, preDatas) {
            let result = [];
            try {
                const outputInfos = this.getOutputInfos(node);
                const inputInfos = this.getInputInfos(node);
                // @ts-ignore
                const cpcRunCode = new Function("preDatas", "inputInfos", "outputInfos", node.cpcRunCode);
                result = cpcRunCode(preDatas, inputInfos, outputInfos);
            } catch (e) {
                console.error("运行函数出错了", e);
            }
            return result;
        }

        getOutputInfos(node) {
            const result = [];
            if (!node.outputs) {
                return result;
            }
            for (let i = 1; i < node.outputs.length; i++) {
                const item = node.outputs[i];
                result.push({
                    name: item.name,
                    type: item.type
                });
            }
            return result;
        }

        getInputInfos(node) {
            const result = [];
            if (!node.inputs) {
                return result;
            }
            for (let i = 1; i < node.inputs.length; i++) {
                const item = node.inputs[i];
                result.push({
                    name: item.name,
                    type: item.type
                });
            }
            return result;
        }

        runPre(node) {
            if (node.properties.preDatas) {
                return node.properties.preDatas;
            }
            let preDatas = [];
            for (let i = 1; i < node.inputs.length; i++) {
                const input = node.inputs[i];
                if (!input.link) {
                    continue;
                }
                const link = this.getLinkById(input.link);
                const preNode = this.getNodeById(link[1]);
                const preSlot = link[2];
                preDatas[i - 1] = this.runPre(preNode)[preSlot - 1];
            }
            node.properties.preDatas = this.runCpcRunCode(node, preDatas);
            console.log("sfsdf",node.title);
            return node.properties.preDatas;
        }

        /**
         * 流程运行
         * @param node
         */
        run(node) {
            const result = this.runPre(node);
            const nextNodes = this.getNextNodes(node);
            if (nextNodes.length == 0) { //没有下一个流程节点
                return;
            }
            //    TODO 判断执行哪个流程
            this.run(nextNodes[0], result);//暂时执行第一个
        }

        /**
         * 启动
         */
        start(data) {

            const router = this.getRouter();
            if (!router) {
                console.error("找不到入口路由");
                return;
            }
            console.time("测试")
            router.properties.preDatas = [data]
            this.run(router);
        }
    }

    var config ={
        "last_node_id": 6,
        "last_link_id": 10,
        "nodes": [
            {
                "id": 1,
                "type": "nodejs/Router",
                "pos": {
                    "0": 100,
                    "1": 200,
                    "2": 0,
                    "3": 0,
                    "4": 0,
                    "5": 0,
                    "6": 0,
                    "7": 0,
                    "8": 0,
                    "9": 0
                },
                "size": [
                    140,
                    60
                ],
                "flags": {},
                "order": 0,
                "mode": 0,
                "inputs": [],
                "outputs": [
                    {
                        "name": "next",
                        "type": "ArrowFlow",
                        "label": "next",
                        "shape": 5,
                        "color_off": "#666",
                        "color_on": "#ff0",
                        "links": [
                            1
                        ]
                    },
                    {
                        "name": "ctx",
                        "type": "Object",
                        "label": "ctx",
                        "shape": 1,
                        "color_off": "#1448ad",
                        "links": [
                            2
                        ]
                    }
                ],
                "title": "路由实例",
                "properties": {
                    "preDatas": [
                        {
                            "name": "name",
                            "value": {
                                "id": 1
                            },
                            "status": true,
                            "type": 1,
                            "list": [
                                1
                            ]
                        }
                    ]
                },
                "cpcRunCode": "\n    return preDatas;\n  "
            },
            {
                "id": 2,
                "type": "basic/ObjectTo",
                "pos": {
                    "0": 300,
                    "1": 200,
                    "2": 0,
                    "3": 0,
                    "4": 0,
                    "5": 0,
                    "6": 0,
                    "7": 0,
                    "8": 0,
                    "9": 0
                },
                "size": {
                    "0": 210,
                    "1": 158
                },
                "flags": {},
                "order": 2,
                "mode": 0,
                "inputs": [
                    {
                        "name": "pre",
                        "type": "ArrowFlow",
                        "label": "pre",
                        "shape": 5,
                        "color_off": "#666",
                        "color_on": "#ff0",
                        "link": 1
                    },
                    {
                        "name": "inputSource",
                        "type": "Object",
                        "label": "输入的对象",
                        "shape": 1,
                        "color_off": "#1448ad",
                        "link": 2
                    }
                ],
                "outputs": [
                    {
                        "name": "next",
                        "type": "ArrowFlow",
                        "label": "next",
                        "shape": 5,
                        "color_off": "#666",
                        "color_on": "#ff0",
                        "links": [
                            4
                        ]
                    },
                    {
                        "name": "name",
                        "type": "String",
                        "links": [
                            9
                        ],
                        "label": "name",
                        "shape": 3,
                        "color_off": "#aaa"
                    },
                    {
                        "name": "value",
                        "type": "Object",
                        "links": null,
                        "label": "value",
                        "shape": 1,
                        "color_off": "#1448ad"
                    },
                    {
                        "name": "status",
                        "type": "Boolean",
                        "links": null,
                        "label": "status",
                        "shape": 3,
                        "color_off": "#ab0909"
                    },
                    {
                        "name": "type",
                        "type": "Number",
                        "links": null,
                        "label": "type",
                        "shape": 3,
                        "color_off": "#34ad19"
                    },
                    {
                        "name": "list",
                        "type": "Array",
                        "links": null,
                        "label": "list",
                        "shape": 1,
                        "color_off": "#9a3434"
                    }
                ],
                "title": "拆分对象",
                "properties": {},
                "cpcRunCode": "\n    const data = preDatas[0];\n    if (!data) {\n      return [];\n    }\n    return outputInfos.map((item) => {\n      return data[item.name];\n    });\n  "
            },
            {
                "id": 3,
                "type": "nodejs/Response",
                "pos": {
                    "0": 917,
                    "1": 246,
                    "2": 0,
                    "3": 0,
                    "4": 0,
                    "5": 0,
                    "6": 0,
                    "7": 0,
                    "8": 0,
                    "9": 0
                },
                "size": [
                    140,
                    60
                ],
                "flags": {},
                "order": 5,
                "mode": 0,
                "inputs": [
                    {
                        "name": "pre",
                        "type": "ArrowFlow",
                        "label": "pre",
                        "shape": 5,
                        "color_off": "#666",
                        "color_on": "#ff0",
                        "link": 5
                    },
                    {
                        "name": "result",
                        "type": 0,
                        "label": "返回结果",
                        "shape": 1,
                        "color_off": "#aaa",
                        "link": 6
                    }
                ],
                "outputs": [],
                "title": "路由响应",
                "properties": {},
                "cpcRunCode": "\n    console.log(\"\\u8DEF\\u7531\\u54CD\\u5E94\\u6253\\u5370\\u8F93\\u51FA\", preDatas[0]);\n    return preDatas;\n  "
            },
            {
                "id": 4,
                "type": "basic/ToObject",
                "pos": {
                    "0": 625,
                    "1": 262,
                    "2": 0,
                    "3": 0,
                    "4": 0,
                    "5": 0,
                    "6": 0,
                    "7": 0,
                    "8": 0,
                    "9": 0
                },
                "size": {
                    "0": 210,
                    "1": 98
                },
                "flags": {},
                "order": 4,
                "mode": 0,
                "inputs": [
                    {
                        "name": "pre",
                        "type": "ArrowFlow",
                        "label": "pre",
                        "shape": 5,
                        "color_off": "#666",
                        "color_on": "#ff0",
                        "link": 4
                    },
                    {
                        "name": "name",
                        "type": "String",
                        "link": 9,
                        "label": "name",
                        "shape": 3,
                        "color_off": "#aaa"
                    },
                    {
                        "name": "data",
                        "type": "Object",
                        "link": 10,
                        "label": "data",
                        "shape": 1,
                        "color_off": "#1448ad"
                    }
                ],
                "outputs": [
                    {
                        "name": "next",
                        "type": "ArrowFlow",
                        "label": "next",
                        "shape": 5,
                        "color_off": "#666",
                        "color_on": "#ff0",
                        "links": [
                            5
                        ]
                    },
                    {
                        "name": "outSource",
                        "type": "Object",
                        "label": "输入的对象",
                        "shape": 1,
                        "color_off": "#1448ad",
                        "links": [
                            6
                        ]
                    }
                ],
                "title": "转为对象",
                "properties": {},
                "cpcRunCode": "\n    const result = {};\n    inputInfos.forEach((item, index) => {\n      result[item.name] = preDatas[index];\n    });\n    return [result];\n  "
            },
            {
                "id": 6,
                "type": "basic/ToObject",
                "pos": {
                    "0": 310,
                    "1": 443,
                    "2": 0,
                    "3": 0,
                    "4": 0,
                    "5": 0,
                    "6": 0,
                    "7": 0,
                    "8": 0,
                    "9": 0
                },
                "size": {
                    "0": 210,
                    "1": 78
                },
                "flags": {},
                "order": 3,
                "mode": 0,
                "inputs": [
                    {
                        "name": "pre",
                        "type": "ArrowFlow",
                        "label": "pre",
                        "shape": 5,
                        "color_off": "#666",
                        "color_on": "#ff0"
                    },
                    {
                        "name": "a",
                        "type": "String",
                        "link": 8,
                        "label": "a",
                        "shape": 3,
                        "color_off": "#aaa"
                    }
                ],
                "outputs": [
                    {
                        "name": "next",
                        "type": "ArrowFlow",
                        "label": "next",
                        "shape": 5,
                        "color_off": "#666",
                        "color_on": "#ff0"
                    },
                    {
                        "name": "outSource",
                        "type": "Object",
                        "label": "输入的对象",
                        "shape": 1,
                        "color_off": "#1448ad",
                        "links": [
                            10
                        ]
                    }
                ],
                "title": "转为对象",
                "properties": {},
                "cpcRunCode": "\n    const result = {};\n    inputInfos.forEach((item, index) => {\n      result[item.name] = preDatas[index];\n    });\n    return [result];\n  "
            },
            {
                "id": 5,
                "type": "basic/CpcString",
                "pos": {
                    "0": 28,
                    "1": 462,
                    "2": 0,
                    "3": 0,
                    "4": 0,
                    "5": 0,
                    "6": 0,
                    "7": 0,
                    "8": 0,
                    "9": 0
                },
                "size": {
                    "0": 210,
                    "1": 78
                },
                "flags": {},
                "order": 1,
                "mode": 0,
                "inputs": [
                    {
                        "name": "pre",
                        "type": "ArrowFlow",
                        "label": "pre",
                        "shape": 5,
                        "color_off": "#666",
                        "color_on": "#ff0"
                    }
                ],
                "outputs": [
                    {
                        "name": "next",
                        "type": "ArrowFlow",
                        "label": "next",
                        "shape": 5,
                        "color_off": "#666",
                        "color_on": "#ff0"
                    },
                    {
                        "name": "输出的数据",
                        "type": 0,
                        "label": "输出的数据",
                        "shape": 1,
                        "color_off": "#aaa",
                        "links": [
                            8
                        ]
                    }
                ],
                "title": "创建字符串",
                "properties": {
                    "preDatas": [
                        "s水电费"
                    ]
                },
                "cpcRunCode": "\n    return preDatas;\n  "
            }
        ],
        "links": [
            [
                1,
                1,
                0,
                2,
                0,
                "ArrowFlow"
            ],
            [
                2,
                1,
                1,
                2,
                1,
                "Object"
            ],
            [
                4,
                2,
                0,
                4,
                0,
                "ArrowFlow"
            ],
            [
                5,
                4,
                0,
                3,
                0,
                "ArrowFlow"
            ],
            [
                6,
                4,
                1,
                3,
                1,
                0
            ],
            [
                8,
                5,
                1,
                6,
                1,
                "String"
            ],
            [
                9,
                2,
                1,
                4,
                1,
                "String"
            ],
            [
                10,
                6,
                1,
                4,
                2,
                "Object"
            ]
        ],
        "groups": [],
        "config": {},
        "extra": {},
        "version": 0.4
    };
    console.log("配置信息", config);
    const paraseLiteFraph = new ParaseLitefraph(config);
    paraseLiteFraph.start(ctx.body);
</script>
</body>
</html>
